// Generics (泛型) 示例
// 演示 Pascal 中泛型的各种用法
program p_35_generics;

{$mode objfpc}{$H+}
// {$mode objfpc} 启用 Object Pascal 模式，支持面向对象编程
// {$H+} 启用长字符串支持（AnsiString）

// 引入单元文件
uses
  SysUtils,        // 系统工具单元，包含常用的系统函数
  Generics.Collections,  // 泛型集合单元
  Generics.Defaults;     // 泛型默认值单元

// 定义一个简单的泛型节点类
type
  TNode<T> = class
  private
    FData: T;
    FNext: TNode<T>;
  public
    constructor Create(const AData: T);
    property Data: T read FData write FData;
    property Next: TNode<T> read FNext write FNext;
  end;

// TNode<T>类的实现
constructor TNode<T>.Create(const AData: T);
begin
  inherited Create;
  FData := AData;
  FNext := nil;
  WriteLn('  创建节点，数据类型: ', TypeName(TypeInfo(T)));
end;

// 定义一个泛型栈类
type
  TStack<T> = class
  private
    FTop: TNode<T>;
    FCount: Integer;
  public
    constructor Create;
    destructor Destroy; override;
    procedure Push(const Item: T);
    function Pop: T;
    function Peek: T;
    function IsEmpty: Boolean;
    function Count: Integer;
  end;

// TStack<T>类的实现
constructor TStack<T>.Create;
begin
  inherited Create;
  FTop := nil;
  FCount := 0;
  WriteLn('  创建泛型栈，元素类型: ', TypeName(TypeInfo(T)));
end;

destructor TStack<T>.Destroy;
begin
  while not IsEmpty do
    Pop;
  inherited Destroy;
end;

procedure TStack<T>.Push(const Item: T);
var
  NewNode: TNode<T>;
begin
  NewNode := TNode<T>.Create(Item);
  NewNode.Next := FTop;
  FTop := NewNode;
  Inc(FCount);
  WriteLn('  入栈: ', Item);
end;

function TStack<T>.Pop: T;
var
  Temp: TNode<T>;
begin
  if IsEmpty then
    raise Exception.Create('栈为空');
    
  Temp := FTop;
  FTop := FTop.Next;
  Result := Temp.Data;
  Temp.Free;
  Dec(FCount);
  WriteLn('  出栈: ', Result);
end;

function TStack<T>.Peek: T;
begin
  if IsEmpty then
    raise Exception.Create('栈为空');
    
  Result := FTop.Data;
end;

function TStack<T>.IsEmpty: Boolean;
begin
  Result := FTop = nil;
end;

function TStack<T>.Count: Integer;
begin
  Result := FCount;
end;

// 定义一个泛型Pair类
type
  TPair<TKey, TValue> = class
  private
    FKey: TKey;
    FValue: TValue;
  public
    constructor Create(const AKey: TKey; const AValue: TValue);
    property Key: TKey read FKey write FKey;
    property Value: TValue read FValue write FValue;
  end;

// TPair<TKey, TValue>类的实现
constructor TPair<TKey, TValue>.Create(const AKey: TKey; const AValue: TValue);
begin
  inherited Create;
  FKey := AKey;
  FValue := AValue;
  WriteLn('  创建Pair，键类型: ', TypeName(TypeInfo(TKey)), '，值类型: ', TypeName(TypeInfo(TValue)));
end;

// 定义一个泛型方法
procedure Swap<T>(var A, B: T);
var
  Temp: T;
begin
  Temp := A;
  A := B;
  B := Temp;
  WriteLn('  交换两个 ', TypeName(TypeInfo(T)), ' 类型的值');
end;

// 定义一个带约束的泛型方法
function Max<T>(A, B: T): T;
begin
  if CompareValue(A, B) > 0 then
    Result := A
  else
    Result := B;
end;

// 定义一个泛型过程，用于显示数组内容
procedure DisplayArray<T>(const Arr: array of T);
var
  i: Integer;
begin
  WriteLn('  数组内容 (类型: ', TypeName(TypeInfo(T)), '):');
  for i := Low(Arr) to High(Arr) do
    WriteLn('    [', i, ']: ', Arr[i]);
end;

// 程序主入口
begin
  WriteLn('=== Pascal 泛型示例 ===');
  WriteLn;
  
  // 1. 使用泛型栈存储整数
  WriteLn('1. 使用泛型栈存储整数:');
  var intStack: TStack<Integer> := TStack<Integer>.Create;
  try
    intStack.Push(10);
    intStack.Push(20);
    intStack.Push(30);
    
    WriteLn('  栈大小: ', intStack.Count);
    WriteLn('  栈顶元素: ', intStack.Peek);
    
    while not intStack.IsEmpty do
      intStack.Pop;
      
    WriteLn('  栈是否为空: ', intStack.IsEmpty);
  finally
    intStack.Free;
  end;
  
  WriteLn;
  
  // 2. 使用泛型栈存储字符串
  WriteLn('2. 使用泛型栈存储字符串:');
  var stringStack: TStack<String> := TStack<String>.Create;
  try
    stringStack.Push('第一个');
    stringStack.Push('第二个');
    stringStack.Push('第三个');
    
    WriteLn('  栈大小: ', stringStack.Count);
    WriteLn('  栈顶元素: ', stringStack.Peek);
    
    while not stringStack.IsEmpty do
      stringStack.Pop;
  finally
    stringStack.Free;
  end;
  
  WriteLn;
  
  // 3. 使用泛型Pair
  WriteLn('3. 使用泛型Pair:');
  var intPair: TPair<String, Integer> := TPair<String, Integer>.Create('年龄', 25);
  try
    WriteLn('  键: ', intPair.Key);
    WriteLn('  值: ', intPair.Value);
  finally
    intPair.Free;
  end;
  
  var stringPair: TPair<Integer, String> := TPair<Integer, String>.Create(1, '第一名');
  try
    WriteLn('  键: ', stringPair.Key);
    WriteLn('  值: ', stringPair.Value);
  finally
    stringPair.Free;
  end;
  
  WriteLn;
  
  // 4. 使用泛型方法
  WriteLn('4. 使用泛型方法:');
  var a, b: Integer;
  a := 10;
  b := 20;
  WriteLn('  交换前: a = ', a, ', b = ', b);
  Swap<Integer>(a, b);
  WriteLn('  交换后: a = ', a, ', b = ', b);
  
  var x, y: String;
  x := 'Hello';
  y := 'World';
  WriteLn('  交换前: x = ', x, ', y = ', y);
  Swap<String>(x, y);
  WriteLn('  交换后: x = ', x, ', y = ', y);
  
  WriteLn;
  
  // 5. 使用泛型数组过程
  WriteLn('5. 使用泛型数组过程:');
  var intArray: array[0..4] of Integer = (1, 2, 3, 4, 5);
  DisplayArray<Integer>(intArray);
  
  WriteLn;
  var stringArray: array[0..2] of String = ('苹果', '香蕉', '橙子');
  DisplayArray<String>(stringArray);
  
  WriteLn;
  
  // 6. 使用泛型集合类
  WriteLn('6. 使用泛型集合类:');
  var stringList: TList<String> := TList<String>.Create;
  try
    stringList.Add('Pascal');
    stringList.Add('FreePascal');
    stringList.Add('Object Pascal');
    
    WriteLn('  字符串列表内容:');
    for var i := 0 to stringList.Count - 1 do
      WriteLn('    ', i, ': ', stringList[i]);
    
    WriteLn('  列表大小: ', stringList.Count);
  finally
    stringList.Free;
  end;
  
  WriteLn;
  
  var intList: TList<Integer> := TList<Integer>.Create;
  try
    intList.Add(100);
    intList.Add(200);
    intList.Add(300);
    
    WriteLn('  整数列表内容:');
    for var i := 0 to intList.Count - 1 do
      WriteLn('    ', i, ': ', intList[i]);
    
    WriteLn('  列表大小: ', intList.Count);
  finally
    intList.Free;
  end;
  
  WriteLn;
  WriteLn('演示了 Pascal 中泛型的各种用法');
  
  // 等待用户按键，防止程序窗口立即关闭
  ReadLn;
end.